#include "CCSpineSprite.h"

NS_CC_BEGIN

//TODO 移出和血量相关的代码

CCSpineSprite::CCSpineSprite() {
    _isFlipX=false;
    
    _barDirty=false;
    _percentage=-1.0f;
    
    _orgVertex=NULL;
    _orgTextureCoord=NULL;
    
}

CCSpineSprite::~CCSpineSprite() {
}

CCSpineSprite* CCSpineSprite::create() {
	CCSpineSprite* spineSprite=new CCSpineSprite();
	return (CCSpineSprite*)spineSprite->autorelease();
}

CCSpineSprite* CCSpineSprite::createWithSpriteFrame(CCSpriteFrame *pSpriteFrame) {
	CCSpineSprite* spineSprite=new CCSpineSprite();
	spineSprite->initWithSpriteFrame(pSpriteFrame);
	return (CCSpineSprite*)spineSprite->autorelease();
}

void CCSpineSprite::setColor(const ccColor4B &c4) {
    bool needUpdate=false;
    if (_realOpacity!=c4.a) {
        CCNodeRGBA::setOpacity(c4.a);
        needUpdate=true;
    }
    if (_realColor.r!=c4.r || _realColor.g!=c4.g || _realColor.b!=c4.b) {
        CCSprite::setColor(ccc3(c4.r, c4.g, c4.b));
    }
    else if(needUpdate) {
        CCSprite::updateColor();
    }
}

void CCSpineSprite::setFlipX(bool bFlipX) {
    if (bFlipX!=_isFlipX) {
        m_bDirty=true;
        _barDirty=true;
        _isFlipX=bFlipX;
    }
}

void CCSpineSprite::updateTransform() {
	CCAssert(m_pobBatchNode, "updateTransform is only valid when CCSprite is being rendered using an CCSpriteBatchNode");
    
    // recalculate matrix only if it is dirty
    if( m_bDirty || _barDirty) {

        // If it is not visible, or one of its ancestors is not visible, then do nothing:
        
        //TODO m_bShouldBeHidden
        
        if (m_bDirty) {
            if( !m_bVisible )
            {
                m_sQuad.br.vertices = m_sQuad.tl.vertices = m_sQuad.tr.vertices = m_sQuad.bl.vertices = vertex3(0,0,0);
            }
            else
            {
                
                //
                // calculate the Quad based on the Affine Matrix
                //
                
                CCSize size = m_obRect.size;
                
                float x1 = m_obOffsetPosition.x;
                float y1 = m_obOffsetPosition.y;
                
                float x2 = x1 + size.width;
                float y2 = y1 + size.height;
                float x = m_transformToBatch.tx;
                float y = m_transformToBatch.ty;
                
                float cr = m_transformToBatch.a;
                float sr = m_transformToBatch.b;
                float cr2 = m_transformToBatch.d;
                float sr2 = -m_transformToBatch.c;
                
                //debug
                //printf("333  %.2f %.2f   %.2f %.2f      %.2f %.2f %.2f %.2f %.2f %.2f \n",x1,y1,size.width,size.height,x,y,cr,sr,cr2,-sr2);
                
                
                float ax = x1 * cr - y1 * sr2 + x;
                float ay = x1 * sr + y1 * cr2 + y;
                
                float bx = x2 * cr - y1 * sr2 + x;
                float by = x2 * sr + y1 * cr2 + y;
                
                float cx = x2 * cr - y2 * sr2 + x;
                float cy = x2 * sr + y2 * cr2 + y;
                
                float dx = x1 * cr - y2 * sr2 + x;
                float dy = x1 * sr + y2 * cr2 + y;
                
                if (_isFlipX) {
                    ax=-ax;
                    bx=-bx;
                    dx=-dx;
                    cx=-cx;
                    if (_percentage>=0.0f) { //_percentage for hp
                        std::swap(ax,bx);
                        std::swap(cx,dx);
                    }
                }
                
                m_sQuad.bl.vertices = vertex3( RENDER_IN_SUBPIXEL(ax), RENDER_IN_SUBPIXEL(ay), m_fVertexZ );
                m_sQuad.br.vertices = vertex3( RENDER_IN_SUBPIXEL(bx), RENDER_IN_SUBPIXEL(by), m_fVertexZ );
                m_sQuad.tl.vertices = vertex3( RENDER_IN_SUBPIXEL(dx), RENDER_IN_SUBPIXEL(dy), m_fVertexZ );
                m_sQuad.tr.vertices = vertex3( RENDER_IN_SUBPIXEL(cx), RENDER_IN_SUBPIXEL(cy), m_fVertexZ );
                
            }
            m_bRecursiveDirty = false;
            m_bDirty=false;
            
            if (_orgVertex) {
                _orgVertex[0]=m_sQuad.bl.vertices;
                _orgVertex[1]=m_sQuad.tr.vertices;
            }
            
        }
        
        if (_barDirty && _percentage>=0.0f) {
            updateBar();
            _barDirty=false;
        }
        
        m_pobTextureAtlas->updateQuad(&m_sQuad, m_uAtlasIndex);

    }

#if CC_SPRITE_DEBUG_DRAW
    // draw bounding box
    CCPoint vertices[4] = {
        ccp( m_sQuad.bl.vertices.x, m_sQuad.bl.vertices.y ),
        ccp( m_sQuad.br.vertices.x, m_sQuad.br.vertices.y ),
        ccp( m_sQuad.tr.vertices.x, m_sQuad.tr.vertices.y ),
        ccp( m_sQuad.tl.vertices.x, m_sQuad.tl.vertices.y ),
    };
    ccDrawPoly(vertices, 4, true);
#endif // CC_SPRITE_DEBUG_DRAW
}

void CCSpineSprite::setTranformToBatch(const CCAffineTransform& transform) {
    if (!CCAffineTransformEqualToTransform(m_transformToBatch,transform)) {
        m_bDirty=true;
        m_transformToBatch=transform;
        if (_percentage>=0.0f) {
            _barDirty=true;
        }
    }
}

void CCSpineSprite::debug() {
    
    ccDrawColor4B(255, 255, 255, 255);
    
    // draw bounding box
    CCPoint vertices[4] = {
        ccp( m_sQuad.bl.vertices.x, m_sQuad.bl.vertices.y ),
        ccp( m_sQuad.br.vertices.x, m_sQuad.br.vertices.y ),
        ccp( m_sQuad.tr.vertices.x, m_sQuad.tr.vertices.y ),
        ccp( m_sQuad.tl.vertices.x, m_sQuad.tl.vertices.y ),
    };
    ccDrawPoly(vertices, 4, true);

}

void CCSpineSprite::setPercentage(float percentage) {
    if (percentage!=_percentage) {
        _percentage=percentage;
        if (m_pobTextureAtlas) {
            _barDirty=true;
        }
        else {
            updateBar();
        }
    }
}

void CCSpineSprite::updateBar() {
    if (!_orgVertex) {
        _orgVertex=(ccVertex3F*)malloc(2 * sizeof(ccVertex3F));
        _orgTextureCoord=(ccTex2F*)malloc(2 * sizeof(ccTex2F));
        
        _orgVertex[0]=m_sQuad.bl.vertices;
        _orgTextureCoord[0]=m_sQuad.bl.texCoords;
        
        _orgVertex[1]=m_sQuad.tr.vertices;
        _orgTextureCoord[1]=m_sQuad.tr.texCoords;
    }
    
    float alpha=clampf(_percentage, 0.0f, 100.0f)/100.0f;
    
    CCPoint min = CCPointZero;
    CCPoint max = ccp(alpha, 1);
    
    m_sQuad.tl.texCoords = textureCoordFromAlphaPoint(ccp(min.x,max.y));
    m_sQuad.tl.vertices = vertexFromAlphaPoint(ccp(min.x,max.y));
    
    m_sQuad.bl.texCoords = textureCoordFromAlphaPoint(ccp(min.x,min.y));
    m_sQuad.bl.vertices = vertexFromAlphaPoint(ccp(min.x,min.y));
    
    m_sQuad.tr.texCoords = textureCoordFromAlphaPoint(ccp(max.x,max.y));
    m_sQuad.tr.vertices = vertexFromAlphaPoint(ccp(max.x,max.y));
    
    m_sQuad.br.texCoords = textureCoordFromAlphaPoint(ccp(max.x,min.y));
    m_sQuad.br.vertices = vertexFromAlphaPoint(ccp(max.x,min.y));
}

ccTex2F CCSpineSprite::textureCoordFromAlphaPoint(CCPoint alpha) {

    CCPoint min = ccp(_orgTextureCoord[0].u,_orgTextureCoord[0].v);
    CCPoint max = ccp(_orgTextureCoord[1].u,_orgTextureCoord[1].v);

    if (m_bRectRotated) {
        CC_SWAP(alpha.x, alpha.y, float);
    }
    return tex2(min.x * (1.0f - alpha.x) + max.x * alpha.x, min.y * (1.0f - alpha.y) + max.y * alpha.y);
}

ccVertex3F CCSpineSprite::vertexFromAlphaPoint(CCPoint alpha) {
    ccVertex3F ret = {0.0f, 0.0f, 0.0f};

    CCPoint min = ccp(_orgVertex[0].x,_orgVertex[0].y);
    CCPoint max = ccp(_orgVertex[1].x,_orgVertex[1].y);
    ret.x = min.x * (1.0f - alpha.x) + max.x * alpha.x;
    ret.y = min.y * (1.0f - alpha.y) + max.y * alpha.y;
    return ret;
}

NS_CC_END